Fractions, division and Bresenham lines

TAD

Introduction

Many years while figuring out how to draw lines using 68000 I had the chance to quickly look at that great bible, Computer Graphics Principles and Practice. At the time I didn't really understand all those pages of maths concerning the Bresenham line algorithm, so came up with a far, far simpler explaination. As far as I know, everyone still uses Bresenham's descriptions to explain how it works. In this article, I'll explain it from a different point of view.

NOTE: This article focuses on the hidden divisions of the Bresenham algorithm.

Lines and division

Let's skip over the dodgy looking ASCII and normal line definitions and start with two end-points (x1,y1) and (x2,y2). We'll consider how to draw a line from (10,20) to (99,39) which gives us a horizontal length of 90 pixels and vertical length of 20 pixels. After dividing the horizontal length (major axis) by the vertical length (minor axis) we get 90/20 = 4.5

In short we need to draw the entire line by using a number of 4.5 horizontal pixel spans.

Fractions and Totals

But we can't draw 0.5 of a pixel, so we must either draw 4 or 5 pixels. To deal with the above problem of 4.5 pixels we seperate the integer part, use that to know how big the span should be and then add the fractional part to a total. Once that total becomes greater or equal to 1.0 we draw an extra pixel.

Think of it this way:

Instead of trying to draw 4.5 pixels then a second 4.5 pixels (ie. 9 pixels), we could draw 4 pixels then 4+1 pixels and still reach our 9.

The very clever part in the Bresenham algorithm is the way it performs 2 divisions using just ADD and SUBTRACT. As we'll see in a short while there is one (very obvious) division for the Integer part and one (slightly hidden) division to obtain the fraction part.

Division through subtraction

As you all know multiplication can be performed using repeated additions (4n = n + n + n + n). Also division can be done through repeated subtraction.

      num = 90
      divisor = 20

      count = 0
      remainder = num
again:
      count = count + 1
      remainder = num - divisor
      if remainder >= divisor then goto again

Running the above code should give you count=4 and remainder=10 which is exactly right.

      mov     bx, 90          ; num = 90
      mov     cx, 20          ; divisor = 20
init:
      mov     ax, 0           ; count = 0
      mov     dx, bx          ; remainder = num
again:
      inc     ax              ; count + 1
      sub     dx, cx          ; remainder - divisor
      cmp     dx, cx          ; is remainder >= divisor ?
      jae     again

Integer division and spans

Okay, there has been nothing ground breaking so far. The previous code performs an integer division just like the DIV and IDIV instructions and gives us the remainder too (remainder = num MOD divisor).

It seems like we can modify it to perform a line drawing algorithm. We plot a pixel inside the above 'span' loop and then re-initialise the remainder and count variables and then loop back to draw the required number of spans (in our example case, 20 of ~4 pixel spans).

example:

      mov     bp, 20          ; number of spans
span:
      mov     bx, 90          ; num = 90
      mov     cx, 20          ; divisor = 20
init:
      mov     ax, 0           ; count = 0
      mov     dx, bx          ; remainder = num
again:
      mov     ES:[di], 5      ; plot pixel, color 5
      inc     di              ; x + 1
      inc     ax              ; count + 1
      sub     dx, cx          ; remainder - divisor
      cmp     dx, cx          ; is remainder >= divisor ?
      jae     again

      add     di, 320         ; y + 1
      dec     bp
      jnz     span            ; another span ?

BUT, we have forgotten about the fraction part.

Performing the above example code will only give us 20 spans of 4 pixels (80 pixels), but we wanted to draw 20 spans of 4.5 pixels (90 pixels!!).

Using remainders to store fractions

You may think we need to use some more variables (or registers) to store the fraction to handle that 0.5 part, but we can simply use the remainder to do this.

      90 / 20 = 4.5           integer part 4
                              fractional part 0.5

      int (90/20) = 4         integer part
        90 mod 20 = 10        remainder

Look closely at that remainder value and the divisor (20).

      10 / 20 = 0.5           fractional part !

      remainder / divisor = fractional part

which is:-
      (num MOD divisor) / divisor = fractional part

If we modify the repeated-subtraction for division so that instead of initialising 'remainder = num' we add to the remainder and do this 'remainder = remainder + num' then that 10 remainder will soon cause an extra iteration of that 'again' loop which will draw that extra pixel.

This means we draw 5 pixels instead of 4. We have totaled up all those 0.5 fractions until we get >= 1.0

Don't worry if you don't understand it, here is some lame QBASIC code.

        CLS
        num = 90
        divisor = 20

        remainder = num

        spancount = 20
span:
        count = 0
again:
        count = count + 1
        remainder = remainder - divisor
        IF remainder >= divisor THEN GOTO again

        PRINT count
        remainder = remainder + num
        spancount = spancount - 1
        IF spancount > 0 THEN GOTO span

Please note how the count value toggles between 4 and 5, this is because we are performing an integer division (using repeated subtraction) AND we are also totaling up all those remainder values of the integer division. Eventually that remainder value (10 in our example) we become large enough to cause an extra iteration of the division loop (10 + 10 = 20, which is >= divisor value).

Closing Words

I hope you understood all that. Sorry if you didn't, just try some different values for yourself (like 10 and 3) and look at the result in count after each span. I still find it amazing that we are able to perform an integer and a fractional divide simply be replacing MOV with an ADD instruction.

Bressy rules.

TAD